using System.Collections.Generic;
using GameFramework.Battle.Core;
using Gameplay.PVE.Config;
using Gameplay.PVE.Effect;
using Gameplay.PVE.Entity;
using Gameplay.PVE.Utils;
using ImageEffects;
using UnityEngine;
using UnityEngine.UI;
using Yoozoo.Libs;
using Yoozoo.Managers;
using Yoozoo.Gameplay.RTS;
using Yoozoo.Mars.Got;

namespace Gameplay.PVE.Skill
{
    public class SkillBullet : IClass
    {
        void IClass.OnReset()
        {
            Dispose(true);
        }

        private struct HitInfo
        {
            public GameObject effect;
            public int effectId;
            public int damage;
        }
        
        protected GameObject bullet;
        protected GameObject staticBullet;
        protected GameObject cameraBullet;
        protected float speedValue = 50f * PveUtils.globalRatio;
        protected Vector3 speed;
        protected Vector3 lastPosition;
        private int targetTeam;
        protected float destroyTime = 0.5f;
        private float startTime;
        private float damage = 10;
        public bool IsDisposed = false;
        public bool IsBornThisFrame = false;
        private Dictionary<int, HitInfo> hitList = new Dictionary<int, HitInfo>();
        protected UnitBase source;
        private int state = 0;
        //private TrailRenderer trail;
        private GameObject trail;

        private bool hasTrail;
        
        private TrailRenderer trailCamera;
        protected float lastTime;

        protected PveSkillBulletConfig config;
        protected List<PveSkillElementConfig> elementConfigs;

        
        private int targetType = 0;//0射人，1射桶

        protected Vector3 targetPosition;
        
        private int directorType;
        private Dictionary<string, float> directorArg;
        protected SkillBase skill;
        private Vector3 startPosition;
        private Vector3 offset;

        protected Vector3 obstaclePosition;

        private bool hasBullet;

        public List<UnitBase> targetUnits;

        protected float currentTime;

        public int id
        {
            get;
            private set;
        }
        
        public void SetTargetAndDirector(Vector3 targetPosition,int directorType,Dictionary<string,float> directorArg)
        {
            this.targetPosition = targetPosition;
            this.directorType = directorType;
            this.directorArg = directorArg;
        }

        public virtual void CheckStartHit()
        {
            CheckHit(startPosition,speed,new Vector3(offset.x,0,offset.z).magnitude);
        }

        public void SetSource(UnitBase source)
        {
            this.source = source;
        }
        
        public virtual void Initialize(PveSkillBulletConfig config,PveSkillConfig skillConfig,SkillBase skill,Vector3 startPosition,Vector3 offset,Vector3 angle,UnitBase source)
        {
            this.IsBornThisFrame = true;
            this.startPosition = startPosition;
            this.skill = skill;
            this.config = config;
            this.offset = offset;
            hasTrail = false;
            speedValue = config.speed * PveUtils.globalRatio;
            var position = startPosition + offset;
            if (speedValue == 0)
            {
                position = skill.targetPosition;
            }

            if (config.model == 0)
            {
                bullet = null;
            }
            else
            {
                bullet = PveResourceManager.GetResource(PveResourceManager.EPveResType.Bullet,  config.model);
                var lightElement = bullet.GetComponent<LightElement>();
                if (lightElement!=null)
                {
                    if (PveMap.rpgLightController)
                    {
                        PveMap.rpgLightController.AddLightElement(lightElement);
                    }
                }
            }
            
            if (bullet == null)
            {
                bullet = new GameObject("bullet");
                hasBullet = false;
            }
            else
            {
                hasBullet = true;
            }
            
            bullet.SetLayerRecursively(skill.targetLayer);
                //bullet.name = "bullet" + config.id;
            bullet.transform.SetParent(PveScene.pveRootTrans);
            bullet.transform.position = position;
            bullet.transform.localEulerAngles = angle;
            float scale = config.model_scale;
            if (scale == 0)
            {
                scale = 1;
            }
            bullet.transform.localScale = new Vector3(scale,scale,scale);
            
            if (config.static_model != 0)
            {
                staticBullet =
                    PveResourceManager.GetResource(PveResourceManager.EPveResType.Bullet, config.static_model);
                if (staticBullet != null)
                {
                    staticBullet.SetLayerRecursively(skill.targetLayer);
                    staticBullet.transform.SetParent(PveScene.pveRootTrans);
                    staticBullet.transform.position = position;
                    staticBullet.transform.forward = bullet.transform.forward;
                    staticBullet.SetActive(true);
                }
            }

                
            speed = (bullet.transform.forward.normalized) * speedValue;

            if (config.trail_effect_id != 0)
            {
                trail = PveResourceManager.GetResource(PveResourceManager.EPveResType.Bullet, config.trail_effect_id);
                if (trail != null)
                {
                    trail.SetLayerRecursively(skill.targetLayer);
                    trail.transform.SetParent(PveScene.pveRootTrans);
                    trail.transform.position = position;
                    trail.transform.localEulerAngles = angle;
                }

                hasTrail = true;
            }

            if (config.bullet_case_effect_id != 0)
            {
                
            }
            
            if (config.screen_shake_mode == 2)
            {
                PveCameraManager.Instance.Shake(0.2f);
            }
            SetSource(source);
            ResetBullet();
            lastPosition = position;
            currentTime = skill.currentTime;
            var d = source.Data;
            this.id = PveBattleBulletsMgr.Ins.GetBulletID(d.id, d.team, this.skill.slotID, this.skill.shootWaveCount);
        }

        public Vector3 GetForward()
        {
            return speed.normalized;
        }

        protected void ResetBullet()
        {
            state = 1;
            
            targetTeam = source.Data.GetTargetTeam(source.Data.searchType);
            float flyDistance = config.max_distance;
            if (config.duration != 0)
            {
                destroyTime = config.duration;
            }
            else
            {
                destroyTime = flyDistance / speedValue;
            }
            startTime = TimeManager.logicTime;
            elementConfigs = new List<PveSkillElementConfig>();
            if (config.elements != null)
            {
                for (int i = 0; i < config.elements.Count; i++)
                {
                    int elementId = config.elements[i];
                    if (elementId == 0)
                    {
                        continue;
                    }
                    elementConfigs.Add(PveUtils.GetSkillElementConfig(elementId));
                }
            }

            IsDisposed = false;
            hitList.Clear();
            lastTime = TimeManager.logicTime;
        }
        
        public void AddExtraElement(int elementId)
        {
            if (!elementConfigs.Contains(PveUtils.GetSkillElementConfig(elementId)))
            {
                elementConfigs.Add(PveUtils.GetSkillElementConfig(elementId));
            }
        }
        
        public void ChangeElement(int oldId,int newId)
        {
            var newConfig = PveUtils.GetSkillElementConfig(newId);
            for (int i = 0; i < elementConfigs.Count; i++)
            {
                if (elementConfigs[i].id == oldId)
                {
                    elementConfigs[i] = newConfig;
                }
            }
        }

        public void RemoveExtraElement(int elementId)
        {
            elementConfigs.Remove(PveUtils.GetSkillElementConfig(elementId));
        }

        private int GetTargetType(Vector3 start,Vector3 dir)
        {
            Ray ray = new Ray(start,dir);
            var casts = Physics.RaycastAll(ray, source.Data.attackRange + 0.2f);
            if (casts.Length > 0)
            {
                PveUtils.Sort(ref casts, (a,b) => { return a.distance > b.distance; });
                for (int i = 0; i < casts.Length; i++)
                {
                    if (int.TryParse(casts[i].transform.gameObject.name,out var id))
                    {
                        var unit = PveManager.Instance.GetUnit(id);
                        if (unit != null)
                        {
                            if (unit.Data.team == source.Data.team)
                            {
                                continue;
                            }
                            else
                            {
                                return 0;
                            }
                        }
                        var hitTarget = PveManager.Instance.GetObstacleUnit(id);
                        if (hitTarget != null && Random.Range(0,1f) < 0.5f)
                        {
                            return 1;
                        }
                    }
                }
                
            }
            return 0;
        }
        
        public virtual void Update(float deltaTime)
        {
            if (IsDisposed)
            {
                return;
            }
            

            if (cameraBullet != null && bullet != null)
            {
                cameraBullet.transform.position = bullet.transform.position;
                cameraBullet.transform.forward = bullet.transform.forward;
            }
            UpdatePosition(deltaTime);
            UpdateTrail();
        }

        public void UpdateTime(float deltaTime)
        {
            currentTime += deltaTime;
        }

        protected virtual void UpdatePosition(float deltaTime)
        {
            if (!IsDisposed)
            {
                //if (hasBullet)
                {
                    Vector3 currentPosition = lastPosition + speed * deltaTime;
                    bullet.transform.position = currentPosition;
                    lastPosition = currentPosition;
                }
                if (TimeManager.logicTime - startTime > destroyTime)
                {
                    Dispose();
                }
            }
        }

        protected virtual void UpdateTrailPosition(Vector3 pos)
        {
            if (hasTrail)
            {
                trail.transform.position = pos;
            }
        }
        
        protected virtual void UpdateTrail()
        {
            if (hasTrail)
            {
                trail.transform.position = bullet.transform.position;
                trail.transform.forward = bullet.transform.forward;
            }
        }

        protected void CheckSubBullets()
        {
            for (int i = 0; i < config.bullets.Count; i++)
            {
                int id = config.bullets[i];
                skill.CreateSubBullet(targetPosition,id);
            }
        }
        
        protected void CheckArea()
        {
            var candidates = UnitManager.Instance.GetAllUnitByTeam(targetTeam);
            if (directorType == (int) EDirectorType.Round)
            {
                float radius = directorArg["radius"];
                for (int i = 0; i < candidates.Count; i++)
                {
                    float distance = Vector3.Distance(targetPosition, candidates[i].Data.position);
                    if (distance <= radius)
                    {
                        HitUnit(candidates[i]);
                    }
                }
            }
            else if (directorType == (int) EDirectorType.RandomRound)
            {
                float radius = directorArg["smallRadius"];
                for (int i = 0; i < candidates.Count; i++)
                {
                    float distance = Vector3.Distance(targetPosition, candidates[i].Data.position);
                    if (distance <= radius)
                    {
                        HitUnit(candidates[i]);
                    }
                }
            }
            else if (directorType == (int) EDirectorType.Single)
            {
                if (targetUnits != null)
                {
                    for (int i = 0; i < targetUnits.Count; i++)
                    {
                        HitUnit(targetUnits[i] as BattleUnit);
                    }
                }
            }
            else if (directorType == (int) EDirectorType.UnSelectable)
            {
                for (int i = 0; i < candidates.Count; i++)
                {
                    HitUnit(candidates[i]);
                }
            }
            else
            {
                if (directorArg.TryGetValue("radius", out var radius))
                {
                    for (int i = 0; i < candidates.Count; i++)
                    {
                        float distance = Vector3.Distance(targetPosition, candidates[i].Data.position);
                        if (distance <= radius)
                        {
                            HitUnit(candidates[i]);
                        }
                    }
                }
                else
                {
                    Debug.LogError(config.id + "子弹的范围技能没有radius");
                }
               
            }
        }

        public void SetLayer(int layer)
        {
            if (bullet != null)
            {
                bullet.SetLayerRecursively(layer);
            }

            if (trail != null)
            {
                trail.SetLayerRecursively(layer);
            }
        }

        public void Pause()
        {
            if (bullet != null)
            {
                var bulletController = bullet.GetComponent<PveEffectController>();
                if (bulletController != null)
                {
                    bulletController.Pause();
                }
            }

            if (trail != null)
            {
                var trailController = trail.GetComponent<PveEffectController>();
                if (trailController != null)
                {
                    trailController.Pause();
                }
            }
        }

        public void Resume()
        {
            if (bullet != null)
            {
                var bulletController = bullet.GetComponent<PveEffectController>();
                if (bulletController != null)
                {
                    bulletController.Resume();
                }
            }

            if (trail != null)
            {
                var trailController = trail.GetComponent<PveEffectController>();
                if (trailController != null)
                {
                    trailController.Resume();
                }
            }
        }

        protected void HitObstacle(ObstacleUnit obstacle,Vector3 position)
        {
            for (int i = 0; i < elementConfigs.Count; i++)
            {
                /*int dmg = -(int)(Random.Range(elementConfigs[i].damage - 1, elementConfigs[i].damage + 2) * source.Data.damageRatio);
                if (elementConfigs[i].type == 3)
                {
                    dmg = 0;
                }
                HitInfo hitInto = new HitInfo
                {
                    effect = effect,
                    effectId = effectId,
                    damage = dmg,
                };*/
                //hitList[battleUnit.Data.id] = hitInto;
                //PveFlyTextManager.Instance.ShowFlyText("Block",obstacle.Data.position + new Vector3(0,1f,0) - Time.deltaTime * 2 * speed);
                float dmg = 1;
                //dmg *= source.Data.damageRatio;
                obstacle.Transmit(ETransmitType.BeHitByOthers);
                int effectId = obstacle.Data.obstacleConfig.hit_effect;
                if (effectId > 0)
                {
                    PveEffectManager.Instance.PlayEffect(effectId,position,speed);
                }
                var arg = ClassManager.Get<AddElementArg>();
                arg.source = source;
                arg.target = obstacle;
                arg.elementConfig = elementConfigs[i];
                arg.bulletPosition = lastPosition;
                arg.isCrit = false;
                arg.rigidBreak = 0;
                arg.sourceSkill = skill;
                obstacle.Transmit(ETransmitType.AddElement,arg);
                ClassManager.Free(arg);
            }
        }

        protected bool HitUnitRegardlessOfType(UnitBase unit,Vector3 position,Transform hitPoint = null)
        {
            if (unit is BattleUnit battleUnit)
            {
                return HitUnit(battleUnit, hitPoint);
            }
            else if (unit is ObstacleUnit obstacleUnit)
            {
                HitObstacle(obstacleUnit, position);
                return false;
            }

            return false;
        }

        protected bool HitUnit(BattleUnit battleUnit, Transform hitPoint = null)
        {
            var isHeadShoot = Random.Range(0,1f) < source.Data.CriticalRate - battleUnit.Data.CriticalReduce;
            return HitUnitWithCrit(battleUnit,hitPoint,isHeadShoot);
        }
        
        protected bool HitUnitWithCrit(UnitBase battleUnit,Transform hitPoint = null,bool isHeadShoot = false)
        {
            //如果是爆头，播放飘字
            /*if (isHeadShoot)
            {
                var offset = PveUtils.GetRandomVector3(new Vector3(-0.5f, -0.1f, -0.5f), new Vector3(0.5f, 0.5f, 0.5f)) * 0.5f;
                PveFlyTextManager.Instance.ShowCritical(battleUnit.Data.position + offset);
                //PveFlyTextManager.Instance.ShowSkillFlyText("20",battleUnit.Data.position);
            }*/
            /*if (skill is SkillMelee)
            {
                Debug.LogError(PveManager.frame + "\t" + source.Data.id + " 近战攻击生效");
            }*/
            /*float rigidBreakRatio = 1;
            if (battleUnit.Data.team != source.Data.team && !PveGlobalVlues.ignoreRigidBreak)
            {
                AddExtraElement(PveGlobalVlues.hitElementId);
            }*/

            if (isHeadShoot && PveGlobalVlues.PlayerCriticalShake)
            {
                PveCameraManager.Instance.Shake(PveGlobalVlues.shakeTime,PveGlobalVlues.shakeRange,PveGlobalVlues.shakeInterval);
            }

            /*if (isHeadShoot)
            {
                rigidBreakRatio *= PveGlobalVlues.criticalRigidBreakRatio;
            }

            int maxRigidBreak = skill.config.rigid_break;
            for (int i = 0; i < elementConfigs.Count; i++)
            {
                if (elementConfigs[i].rigid_break > maxRigidBreak)
                {
                    maxRigidBreak = elementConfigs[i].rigid_break;
                }
            }*/
            for (int i = 0; i < elementConfigs.Count; i++)
            {
                int effectId = 0;
                float scale = 1;
                var forward = source.Data.position - battleUnit.Data.position;
                /*var position = battleUnit.Data.position +
                                                PveUtils.globalRatio * new Vector3(Random.Range(-0.3f,0.3f), Random.Range(-0.7f,0.7f), Random.Range(-0.3f,0.3f)) + new Vector3(0,PveUtils.globalRatio,0);*/
                /*if (config.effectId != 0)
                {
                    effectId = config.effectId;
                }
                else */
                bool isNormalAttackDamage = false;
                int outputType;
                if (elementConfigs[i].element_type == 1 &&
                    elementConfigs[i].element_param.TryGetValue("OutputType", out outputType))
                {
                    isNormalAttackDamage = outputType == 1;
                }
                if (battleUnit.Data.CurrentShield > 0)
                {
                    
                }
                else if (battleUnit.Data.modelId == PveGlobalVlues.AirDroneModelId || battleUnit.Data.modelId == 10001 || battleUnit.Data.modelId == PveGlobalVlues.HelicopterModelId)
                {
                    if (isNormalAttackDamage)
                    {
                        effectId = (int) ESkillEffect.hitObstacleCar;
                    }
                    else
                    {
                        effectId = 0;
                    }
                }
                else if (isHeadShoot)
                {
                    effectId = config.critical_effect;
                    forward = -forward;
                }
                else if (config.hit_effect > 0)
                {
                    effectId = config.hit_effect;
                    forward = -forward;
                }

                if (effectId != 0)
                {
                    if (hitPoint != null)
                    {
                        
                        if (isHeadShoot)
                        {
                            PveEffectManager.Instance.PlayEffect(effectId, hitPoint.position, forward,5,0,hitPoint.transform);
                            var groundPosition = hitPoint.position;
                            groundPosition.y = 0.01f;
                            PveEffectManager.Instance.PlayEffect((int)ESkillEffect.hitRoleHeadGround,groundPosition , forward,5,0);
                        }
                        else
                        {
                            if (Random.Range(0, 1f) < PveGlobalVlues.hitEffectRate)
                            {
                                PveEffectManager.Instance.PlayEffect(effectId, hitPoint.position, forward,5,0,hitPoint.transform);
                                PveEffectManager.Instance.PlayEffect(13, new Vector3(hitPoint.position.x,0,hitPoint.position.z), forward);
                            }
                            
                        }
                    }
                    else
                    {
                        var list = battleUnit.Data.hitPoints;
                        if (list.Count == 0)
                        {
                            var position = lastPosition + TimeManager.LogicDeltaTime * speed;
                            PveEffectManager.Instance.PlayEffect(effectId, position, forward,5,0,battleUnit.gameObject.transform);
                        }
                        else
                        {
                            hitPoint = battleUnit.Data.hitPoints[Random.Range(0, list.Count)];
                            var position = hitPoint.position + PveUtils.GetRandomVector3(new Vector3(-0.2f, -0.2f, -0.2f), new Vector3(0.2f, 0.2f, 0.2f));
                            PveEffectManager.Instance.PlayEffect(effectId, position, forward,5,0,hitPoint.transform);
                        }
                    }
                }
                HitInfo hitInto = new HitInfo
                {
                    damage = 0,
                };
                hitList[battleUnit.Data.id] = hitInto;

                var arg = ClassManager.Get<AddElementArg>();
                arg.source = source;
                arg.target = battleUnit;
                arg.elementConfig = elementConfigs[i];
                arg.bulletPosition = lastPosition;
                arg.isCrit = isHeadShoot;
                arg.id = this.id;
                //if (PveGlobalVlues.ignoreRigidBreak)
                {
                    arg.rigidBreak = 0;
                }
                /*else
                {
                    int baseRigidBreak = maxRigidBreak;
                    arg.rigidBreak = (baseRigidBreak * rigidBreakRatio * source.Data.rigidRatio);
                }*/
               
                arg.sourceSkill = skill;
                battleUnit.Transmit(ETransmitType.AddElement,arg);
                ClassManager.Free(arg);
                
                /*if (PveManager.Instance.CheckNeedPlayFinalHit(battleUnit))
                {
                    //PveManager.Instance.PlayFinalHit(bullet, battleUnit,1);
                    //PveManager.Instance.RpgToNext();
                    return false;
                }*/
            }
            if (isHeadShoot)
            {
                source.Transmit(ETransmitType.Critical);
            }

            if (source.Data.isManualMoving && !PveManager.Instance.isInPve)
            {
                PveCameraManager.Instance.Shake(0.04f,0.1f);
            }
            
            if (skill.skillType == 0) //普攻命中
            {
                source.Transmit(ETransmitType.ShootHit);
                if (source.Data.team != battleUnit.Data.team)
                {
                    var sarg = ClassManager.Get<BeHitByOthersArg>();
                    sarg.source = source;
                    battleUnit.Transmit(ETransmitType.GetShootHit,sarg);
                    ClassManager.Free(sarg);
                }
                
            }
            
            return true;
        }
        
        protected virtual void CheckHit(Vector3 startPosition,Vector3 direction,float length,bool considerObstacle = false)
        {
            var casts = Physics.RaycastAll(startPosition, direction, length,PveUtils.pveLogicLayer);
            for (int i = 0; i < casts.Length; i++)
            {
                int id;
                if (!int.TryParse(casts[i].transform.gameObject.name, out id))
                {
                    Debug.LogEditorError(casts[i].transform.gameObject.name + "检测到碰撞体");
                    continue;
                }
                if (hitList.ContainsKey(id))
                {
                    continue;
                }

                bool hasHit = false;

                int dmg = -(int) Random.Range(damage - 1, damage + 1);
                var battleUnit = PveManager.Instance.GetUnit(id);
                if (battleUnit != null && battleUnit.Data.team == targetTeam)
                {
                    hasHit = HitUnit(battleUnit);
                }
                else
                {
                    var obstacle = PveManager.Instance.GetObstacleUnit(id);
                    considerObstacle = considerObstacle && Random.Range(0, 1f) < 0.5f;
                    if (obstacle != null && considerObstacle)
                    {
                        HitObstacle(obstacle,obstacle.Data.position);
                        hasHit = true;
                    }
                }

                if (hasHit && config.destroy_type == 1)
                {
                    Dispose();
                    break;
                }
            }
              
        }

        public virtual void Dispose(bool isForceDestroy = false)
        {
            if (IsDisposed || config == null)
            {
                return;
            }
            
            IsDisposed = true;

            if (!isForceDestroy)
            {
                if (config.destroy_effect_id != 0 && bullet != null)
                {
                    PveEffectManager.Instance.PlayEffect(config.destroy_effect_id,bullet.transform.position,bullet.transform.forward,5,config.destroy_effect_scale);
                }

                if (config.screen_shake_mode == 1)
                {
                    PveCameraManager.Instance.Shake(0.2f);
                }
            }
            
            if (bullet != null)
            {
                if (hasBullet)
                {
                    var lightElement = bullet.GetComponent<LightElement>();
                    if (lightElement!=null)
                    {
                        if (PveMap.rpgLightController)
                        {
                            PveMap.rpgLightController.RemoveLightingElement(lightElement);
                        }
                    }
                    PveResourceManager.RecoverResource(bullet,PveResourceManager.EPveResType.Bullet,config.model);
                }
                else
                {
                    GameObject.Destroy(bullet);
                }
            }
            
            if (cameraBullet != null)
            {
                PveResourceManager.RecoverResource(cameraBullet,PveResourceManager.EPveResType.Bullet,config.model);
            }

            if (staticBullet != null)
            {
                PveResourceManager.RecoverResource(staticBullet,PveResourceManager.EPveResType.Bullet,config.static_model);
                staticBullet = null;
            }
                
            if (hasTrail)
            {
                var trail = this.trail;
                int id = config.trail_effect_id;
                if (isForceDestroy)
                {
                    PveResourceManager.RecoverResource(trail,PveResourceManager.EPveResType.Bullet,id);
                }
                else
                {
                    TimeManager.Instance.DelayCall(300, () =>
                    {
                        PveResourceManager.RecoverResource(trail,PveResourceManager.EPveResType.Bullet,id);
                    });
                }
                this.trail = null;
                hasTrail = false;
            }

            targetUnits = null;
            hitList.Clear();
            bullet = null;
            cameraBullet = null;
            
            PveBattleBulletsMgr.Ins.OnBulletDispose(this.id);
           
            
            //TimeManager.Instance.DelayCall(50, () =>
            //{
                 
                

                
                
                //});
        }
    }
}